/**************************************************************************(C)*
 *
 *  This file is part of the GreenHills project
 *  Copyright (C) 2009  Tieto Corporation
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  Not for commmercial use. Only with Tieto permission.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************(C)*/

#pragma once

#include <QString>
#include "gpsdll.h"

namespace greenhills {

namespace util {
    class obinstream;
    class ibinstream;
}

namespace gps {

/** @brief Encapsulation of GPS coordinate
 *
 * This class encapsulates GPS coordinate and provides basic operations like
 * assignment, comparison and streaming.
 */

class GH_GPS_CLASS CGPSCoordinate
{
public:
    static const long COORD_1_MINUTE = 10000;
    static const long COORD_1_DEGREE = (60*COORD_1_MINUTE);

public:
    /**
     * @brief Creates empty CGPSCoordinate object
     */
    CGPSCoordinate();

    /**
     * @brief Creates CGPSCoordinate object from given coordinate value.
     *
     * @param pCoordinate Terrestial coordinate value in float format
     * XXYY.ZZZZ where XX is value in terrestial longitude degrees, YY.ZZZZ is
     * the value in terrestial longitude minutes with decimal part. Positive
     * value represents North latitude or East longitude. Negative value
     * represents South latitude or West longitude.
     */
    CGPSCoordinate(long pLatitude);

public:
    /**
     * @brief Returns latitude position
     *
     * @return Latitude position where one step equals to 0.0001'. Positive value
     * means North or West latitude, negative value means South or East latitude.
     */
    long coordinate() const {return mCoordinate;}

    /**
     * @brief Returns latitude position in radians
     *
     * @return Latitude position where 0 equals to equator or zero meridian.
     * Positive value means North or West latitude, negative value means South
     * or East latitude.
     */
    virtual double toRad() const;

    /**
     * @brief Returns GPS coordinate as a string
     *
     * @return Longitude position in a string format. The string format is
     * in human readable format AA BB.bbbb {N/S}, CC DD.dddd {E/W}.
     */
    virtual QString toString() const
        { return toString("%02i\260%07.4f", '+', '-'); }

public:
    /**
     * @brief Assigns GPS position value.
     *
     * @param pPosition A new GPS position value.
     * @return Longitude position in human readable format AA BB.bbbb {E/W}.
     */
    const CGPSCoordinate& operator =(
            const CGPSCoordinate &pPosition);

    /**
     * @brief Compares two GPS positions.
     *
     * @param pPosition A GPS position value to be compared with.
     * @return Returns true if then given GPS positions are the same.
     */
    bool operator == (const CGPSCoordinate &pPosition);

    /**
     * @brief Stores GPS positionto a stream
     *
     * @param pStream A stream object where GPS position value is written to.
     * @return Returns the stream object passed as parameter.
     */
    virtual util::obinstream& operator<<(util::obinstream &pStream) const;

    /**
     * @brief Restores GPS position from a stream
     *
     * @param pStream A stream object where GPS position value is read from.
     * @return Returns the stream object passed as parameter.
     */
    virtual util::ibinstream& operator>>(util::ibinstream &pStream);

protected:
    QString toString(const char *pFormatString,
            char pPosSuffix, char pNegSuffix) const;
    static CGPSCoordinate fromString(const QString &str,
            char pPosSuffix, char pNegSuffix);

private:
    long mCoordinate;
};

class GH_GPS_CLASS CGPSLatitude : public CGPSCoordinate
{
public:
    virtual QString toString() const
        {return CGPSCoordinate::toString("%02i\260%06.3f", 'N', 'S');}

    virtual double toRad() const;

    static CGPSCoordinate fromString(const QString &str);
};

class GH_GPS_CLASS CGPSLongitude : public CGPSCoordinate
{
public:
    virtual QString toString() const
        {return CGPSCoordinate::toString("%03i\260%06.3f", 'E', 'W');}

    virtual double toRad() const;

    static CGPSCoordinate fromString(const QString &str);
};

} //namespace gps
} //namespace greenhills
